iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Kubernetes

不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA系列 第 5

Day 5|第一個 Pod:Kubernetes 為什麼不直接管理 Container?

  • 分享至 

  • xImage
  •  

今天開始來建立第一個真正屬於我們的 Kubernetes Workload。

但先回答一個很重要的問題。

既然 Kubernetes 管 Container:

為什麼最小單位不是 Container,而是 Pod?


Pod 是 Kubernetes 最小可部署單位

最簡單情況:

Pod
└── Container

所以初學時很容易覺得:

Pod 就等於 Container。

其實不是。

一個 Pod 可以有多個 Container:

Pod
├── Main Container
└── Sidecar Container

Q: Sidecar Container(邊車容器)是啥?

它是一種在分散式架構與 Kubernetes 中常見的設計模式:將輔助功能從主應用程式中拆分出來,打包成獨立的容器,並與主應用容器部署在同一個 Pod(或同一個生命週期單元)中協同運作。

其名稱來自於摩托車旁的「邊車」(Sidecar)
用這張圖來表示應該就很好理解XD
https://ithelp.ithome.com.tw/upload/images/20260907/20168537PUt4YT7Wcf.jpg

——主容器就像摩托車本體負責驅動前進(核心業務邏輯),而 Sidecar 就像掛在旁邊的邊車,提供額外支援(監控、日誌收集、代理),兩者同進同退。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537qHO5KbSmCL.png

又因都位在同一個 Pod,裡面的 Container 便可共享一些資源,例如 Network Namespace。

因此它們可以透過:

localhost

互相溝通。

可以把 Pod 理解成:

Kubernetes 對一組「必須一起生活」的 Container 提供的執行邊界。

但大多數情況,若沒特殊需求.
一個 Pod 還是只有一個主要 Application Container。


建立第一個 Pod

先用最快的方式:

kubectl run nginx \
  --image=nginx:alpine

查看:

kubectl get pods

可能一開始:

ContainerCreating

稍後變:

Running

https://ithelp.ithome.com.tw/upload/images/20260907/20168537cT7YAg78Ct.png

這個過程代表:

Pod Object 建立
↓
Scheduler 選 Node
↓
kubelet 收到任務
↓
取得 nginx Image
↓
建立 Container

看它到底跑在哪一台 Node

kubectl get pods -o wide

-o wide 代表:

顯示更多欄位。

除了 Pod Name、Status,還可以看到:

IP
NODE

https://ithelp.ithome.com.tw/upload/images/20260907/20168537TX3uUlOZzE.png

例如:

nginx   Running   10.x.x.x   cka-lab-worker

也就是 Scheduler 已經幫我們決定了 Node。


describe 是你未來最重要的指令之一

kubectl describe pod nginx

內容很多。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537Bz0lmRFODH.png
https://ithelp.ithome.com.tw/upload/images/20260907/20168537kJp5WMulwz.png

現在不用全部看懂。

先找到:

Node
Containers
Conditions
Events

尤其:

Events

未來非常重要。

如果:

Pod Pending
ImagePullBackOff
Probe Failed
Volume 掛不上

很多線索都會出現在這裡。


查看 Application Log

kubectl logs nginx

這個指令查看 Container 寫到:

stdout
stderr

的內容。

也就是 Application Log。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537KIoe9Rijt0.png


直接進 Container

kubectl exec -it nginx -- sh

拆開。

kubectl exec

在 Container 裡執行 Command。

-i

保持 stdin。

-t

提供 Terminal。

--

代表:

後面開始是 Container 裡要執行的 Command。

最後:

sh

在 Container 裡啟動 Shell。

進去後:

hostname

可能看到 Pod 名稱。

exit

離開。

https://ithelp.ithome.com.tw/upload/images/20260907/20168537MUA7IyChYA.png


Imperative 與 Declarative

我們剛剛:

kubectl run

例如:

kubectl run nginx \
  --image=nginx:alpine

幫我做一件事情:
要求 Kubernetes 建立一個名為 nginx 的 Pod,並在裡面運行一個基於 nginx:alpine 映像檔的容器。

這種直接透過指令告訴 Kubernetes 的方式稱為:

Imperative (命令式)

但 Kubernetes 更核心的方式是:

Declarative (宣告式)

先個別建立對應的 yaml:

pod.yaml

例如:

apiVersion: v1

kind: Pod

metadata:
  name: nginx

spec:
  containers:
    - name: nginx
      image: nginx:alpine

然後再透過 apply 針對該 yaml 去建立起來

kubectl apply -f pod.yaml

這不是在說:

請執行某個步驟。

而是在說:

我希望 Cluster 裡存在一個符合這個描述的 Pod。

這就是 Desired State。

Imperative vs Declarative 比較表:

比較維度 命令式 (Imperative) 宣告式 (Declarative)
核心觀念 怎麼做 (How):逐步下達操作指令 期望狀態 (What):定義最終期望的目標狀態
主要操作 直接執行指令(如 run, create, expose 撰寫 YAML / JSON 檔案並交由系統對齊狀態
典型指令 kubectl run nginx --image=nginx kubectl scale deployment/web --replicas=3
版本控管 (GitOps) 困難(指令操作不易追蹤歷史變更) 優良(Manifest 檔案可納入 Git 進行版控與 Code Review)
可重複性與維護性 低(重複執行容易報錯,難以稽核) 高(具備冪等性,適合自動化 CI/CD 流水線)
適用情境 臨時排查、快速測試、除錯一次性任務 正式環境 (Production)、團隊協作、長期維護的基礎架構

YAML 四個最重要區塊

幾乎所有 Kubernetes YAML 都會看到:

apiVersion:

kind:

metadata:

spec:

以下進行解釋:
Kubernetes 的 YAML 設定檔(Manifest)主要由這四個頂層欄位組成,針對各欄位的詳細說明與底層邏輯整理如下:


1. apiVersion(API 版本與群組)

apiVersion 用來告訴 Kubernetes API Server 該用哪一個版本的 API schema 來解析並處理這份定義。

它的格式主要有兩種:

  • 單純版本v1
  • 群組/版本 (Group/Version)<api-group>/<version>,例如 apps/v1batch/v1

關於 /api/apis 的底層差別

/api/apis 是 Kubernetes API Server 的 RESTful 端點路徑

  • API 核心路徑 主要分成這兩個
    • /api:這是 Core API 的入口(歷史遺留原因,最早的 K8s 資源都在這)。
    • /apis:這是 Named API Groups 的入口(後來新增的、擴展的資源都歸類於此)。
  • Core API Group(又稱 Legacy Group)

  • API URL 端點/api/v1

  • 特點:Kubernetes 最早期的核心資源,沒有命名群組(Group name 為空字串 "")。

  • YAML 寫法:直接寫 apiVersion: v1

  • 常見資源PodServiceNamespaceConfigMapSecretNode

  • Named Groups

  • API URL 端點/apis/<group>/<version>

  • 特點:後來為了模組化與擴充性引入的資源群組。

  • YAML 寫法<group>/<version>

  • 常見範例

    • apps/v1DeploymentStatefulSetDaemonSet
    • batch/v1JobCronJob
    • networking.k8s.io/v1IngressNetworkPolicy
    • rbac.authorization.k8s.io/v1RoleClusterRole

查詢小技巧:如果不確定某個資源要填什麼 apiVersion,可以直接在終端機執行:

kubectl explain <資源名稱>
# 例如:kubectl explain pod 或 kubectl explain deployment

第一行就會清楚標示出該資源對應的 VERSIONKIND
https://ithelp.ithome.com.tw/upload/images/20260907/20168537yocsIuK9p0.png


2. kind(資源類別)

告訴 Kubernetes 你想要建立哪一種物件。

  • 本質:決定了這個物件在 K8s 內部代表的實體類型與控制邏輯(Controller)。
  • 格式注意:嚴格區分大小寫,採用 PascalCase(大駝峰命名法)。例如必須寫 DeploymentServicePod,不能寫成全小寫或混用。
  • 與 apiVersion 的連動:同一個 kind 名稱可能在不同 API 版本有不同定義(例如過去曾有 extensions/v1beta1 的 Deployment,後來演進為 apps/v1)。

3. metadata(識別與元數據)

定義該物件的「身份識別資料」以及附加的管理標籤,主要給人類、Controller 或外部工具進行識別與篩選。

主要包含的欄位:

  • name(必要):同一個 Namespace 底下,相同 kind 的資源名稱必須唯一。
  • namespace(選填):指定該資源屬於哪個邏輯隔離區塊。若未填寫,預設會部署在當前 Context 所屬的 Namespace(通常是 default)。
  • labels(鍵值對):用於識別與選取。例如給 Service、Deployment 的 selector 來過濾關聯哪些 Pod。
  • annotations(鍵值對):用於附帶額外非識別資訊。通常給監控工具、CI/CD 系統或 Ingress Controller 讀取設定(例如流量路由權重、Prometheus 採集開關)。

4. spec(期望規格 Specification)

這是整個 YAML 的核心,代表你期望該物件達到的最終狀態(Desired State)

  • 宣告式核心:你描述 spec,Kubernetes 的 Controller 就會不斷執行 Reconciliation Loop(是一種不斷將「實際狀態」調整為「期望狀態」的自動化控制機制),努力讓叢集的實際狀態(Current State / status)與 spec 保持一致。

  • 結構依 Resource 而異:不同 kindspec 內容完全不同:

  • Podspec:定義有哪些容器(containers)、掛載哪些硬碟(volumes)、重啟策略(restartPolicy)等。

  • Deploymentspec:定義要複製幾份(replicas)、更新策略(strategy)、以及用來產生 Pod 的範本(template)。

  • Servicespec:定義轉發規則(ports)、型態(type: ClusterIP / NodePort / LoadBalancer)、選取哪些 Pod(selector)。

  • 少數例外:並非所有物件都有 spec。例如純粹存放資料的 ConfigMapSecret,主要的設定內容欄位是 data / stringData,就沒有 spec 區塊。


完整對照範例

apiVersion: apps/v1                 # 具名群組 apps 下的 v1 版本 (端點在 /apis/apps/v1)
kind: Deployment                    # 大駝峰命名,宣告要建立 Deployment 物件
metadata:
  name: nginx-deployment            # 物件唯一名稱
  labels:
    app: my-nginx                   # 供日後過濾或查詢的標籤
spec:                               # 期望狀態定義
  replicas: 2                       # 期望維持 2 個 Pod
  selector:
    matchLabels:
      app: my-nginx
  template:                         # 底下定義 Pod 範本 (屬於 Pod 的 metadata 與 spec)
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80


刪掉 Pod 會怎樣?

kubectl delete pod nginx

再:

kubectl get pods

你會發現:

沒了。

它不會自己回來。

這是一個超級重要的觀察。

因為現在只是:

孤獨的 Pod。

沒有 Controller 管它。

所以:

Pod 死掉
=
真的死掉。

那要如何避免呢?
明天開始,我們就會解決這個問題。


上一篇
Day 4|不用花一毛錢:用 kind 在自己的電腦建立三節點 Kubernetes Cluster
下一篇
Day 6|Label、Selector、Namespace:Kubernetes 是怎麼找到「自己人」的?
系列文
不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言